
#include "xmodule_config.h" 


#if MODULE_CHECK_ENABLED( RTC )

#include <string.h>

#include "rtl876x.h"
#include "rtl876x_rcc.h"
#include "rtl876x_rtc.h" 
#include "rtl876x_nvic.h"

#include "em_rtc.h"

#if MODULE_CHECK_LOG_ENABLED( RTC )
#include "log.h"
#define LOG     LOG_INFO
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#endif 

#define CLOCK_CMP_CHANNEL_IDX       0 

#ifndef CLOCK_SOURCE_FREQ
#define CLOCK_SOURCE_FREQ           32000
#endif

#define CLOCK_MINUTE_CHANNEL_IDX    1 

static volatile uint32_t ticks = 0; 
static volatile uint32_t last_ticks = 0;

static em_rtc_evt_handle_t m_cb = NULL;
static uint32_t pre_rtc_tick_count; 

static rtc_t rtc_now;


static void driver_configs(void)
{
    RTC_DeInit();
    RTC_SetPrescaler( 0 ); 
    RTC_MaskINTConfig( RTC_INT_COMP0, ENABLE ); 
    RTC_INTConfig( RTC_INT_COMP0, DISABLE ); 
    
    
    NVIC_InitTypeDef nvicInitStruct;
    nvicInitStruct.NVIC_IRQChannel              = RTC_IRQn;
    nvicInitStruct.NVIC_IRQChannelPriority      = 3; 
    nvicInitStruct.NVIC_IRQChannelCmd           = ENABLE;
    NVIC_Init( &nvicInitStruct ); 
    
    RTC_SystemWakeupConfig( ENABLE );      
}

void RTC_Handler(void)
{
    if( RTC_GetINTStatus( RTC_INT_COMP0) == SET ) 
    {
        pre_rtc_tick_count = RTC_GetCounter();
        uint32_t diff = 60 - rtc_now.cur.second;
        ticks += diff;
        rtc_second_add( &rtc_now, diff );

        uint32_t compare = (RTC_GetCompValue( 0 ) + 60 * EM_RTC_TOTICKS(1000) ) & 0xFFFFFF;         
        RTC_SetCompValue( 0, compare ); 
        RTC_ClearCompINT( 0 );

        if( m_cb != NULL ) 
        {
            m_cb(); 
        }
    }

    if( RTC_GetINTStatus(RTC_INT_OVF) == SET ) 
    {
        RTC_ClearOverFlowINT();
    }
}
static void em_rtc_start(void)
{
    uint32_t diff = 60 - rtc_now.cur.second;
    pre_rtc_tick_count = RTC_GetCounter();
    uint32_t compare = (RTC_GetCounter() + diff * EM_RTC_TOTICKS(1000) ) & 0xFFFFFF; 
        
    RTC_SetCompValue( 0, compare );
    RTC_ClearCompINT( 0 );
    
    RTC_MaskINTConfig( RTC_INT_COMP0, DISABLE ); 
    RTC_INTConfig( RTC_INT_COMP0, ENABLE ); 
    RTC_NvCmd( ENABLE );
    RTC_RunCmd( ENABLE );     
}

uint32_t em_rtc_get_second_ticks(void)
{
    uint32_t count = RTC_GetCounter();
    uint32_t diff;
    if( count >= pre_rtc_tick_count )
    {
        diff = (count - pre_rtc_tick_count ) / CLOCK_SOURCE_FREQ;
    }
    else 
    {
        diff = (count + 0xffffff - pre_rtc_tick_count ) / CLOCK_SOURCE_FREQ;
    }

    return ticks + diff; 
}

void em_rtc_init(void)
{    
    driver_configs();
    // em_rtc_start();
}

void em_rtc_register_callback( em_rtc_evt_handle_t cb ) 
{
    m_cb = cb; 
}

void em_rtc_set_now(datetime_t *p_dt)
{    
    RTC_RunCmd( DISABLE );
    rtc_update( &rtc_now, p_dt );

    em_rtc_start();
}

void em_rtc_get_now(datetime_t *p_dt)
{
    memcpy( p_dt, &rtc_now.cur, sizeof(datetime_t) );

    uint32_t count = RTC_GetCounter();
    uint32_t diff_seconds ;
    
    uint32_t total;
    if( count >= pre_rtc_tick_count )
    {
        total = (count - pre_rtc_tick_count);
        // diff_seconds = total / CLOCK_SOURCE_FREQ;
        // millsecond = ((total % CLOCK_SOURCE_FREQ) * 1000) / CLOCK_SOURCE_FREQ;
        // diff_seconds = (count - pre_rtc_tick_count) / CLOCK_SOURCE_FREQ;        
    }
    else 
    {
        total = count + 0xffffff - pre_rtc_tick_count; 
        // diff_seconds = (count + 0xffffff - pre_rtc_tick_count) / CLOCK_SOURCE_FREQ; 

    }
    diff_seconds = total / CLOCK_SOURCE_FREQ;
    p_dt->second += diff_seconds;

#if CLOCK_SUPPORT_MILLISECONDS
    uint32_t millsecond;
    millsecond = ((total % CLOCK_SOURCE_FREQ) * 1000) / CLOCK_SOURCE_FREQ;
    p_dt->millsecond = millsecond; 
#endif    
    
}
uint32_t em_rtc_get_now_timestamp(void)
{
    return rtc_get_timestamp_by( &rtc_now.cur );
}


uint32_t em_rtc_get_ticks(void)
{
    return RTC_GetCounter();
}

void em_rtc_calc_time(uint32_t s, uint32_t e,  em_rtc_time_t * p_rtc_time)
{
    uint32_t diff = (e - s) & 0xFFFFFFUL;

    p_rtc_time->seconds = diff / CLOCK_SOURCE_FREQ;
    p_rtc_time->tail = diff % CLOCK_SOURCE_FREQ;  
}

uint32_t em_rtc_get_diff( uint32_t s, uint32_t e)
{
    return  (e - s) & 0xFFFFFFUL;
}

bool em_rtc_check_time_expired( uint32_t s, uint32_t RTC_MS)
{
    uint32_t val = RTC_GetCounter();
    return ((val - s ) & 0xFFFFFFUL) > RTC_MS;
}

uint32_t em_rtc_ticks_to_ms(uint32_t ticks)
{
    return EM_RTC_TOMS(ticks);
}

//////////////////////////////////////////////
uint32_t iqw_module_rtc_get_ticks(void)
{
    return RTC_GetCounter();
}

#endif
